using AnimCollections;
using AOT;
using Unity.Burst;
using UnityEngine.Animations;
using UnityEngine.Playables;

namespace DA.AnimGraph {
    [BurstCompile]
    public unsafe partial struct StateMachineNode : INode {
        public struct SetupData : INodeSetupData {
            public TransitionDesc[] transitionsDesc; // 走编辑器要按 sourceStateId 先排好序
            public IntLinkDesc defaultStateIndex;
        }

        //
        private StateMachineTransitionInfo transitionInfo;
        private IntLink defaultState;
        private TransitionEvaluator transitionEvaluator;

        //
        private NodeHead head;
        private AnimationMixerPlayable playable;
        private int currentState;

        [BurstCompile]
        [MonoPInvokeCallback(typeof(NodeLink.DisposeDelegate))]
        private static bool Dispose(in void* node) {
            var self = (StateMachineNode*)node;

            self->transitionInfo.Dispose();
            self->transitionEvaluator.Dispose();
            return true;
        }

        private void Setup(in SetupData data, ref GraphBuffer buffer, in NodeLink* link) {
            transitionInfo = new StateMachineTransitionInfo(data.transitionsDesc, link->childrenCount, ref buffer);
            defaultState = new IntLink(data.defaultStateIndex);

            transitionEvaluator = new TransitionEvaluator(5, ref buffer);
        }

        private static Playable BuildPlayableGraph(in void* node, in NodeLink* link, in PlayableGraph graph, in BuildContext buildContext) {
            var self = (StateMachineNode*)node;

            self->head = new NodeHead(link);

            int childrenCount = self->head.childrenCount;
            self->playable = AnimationMixerPlayable.Create(graph, childrenCount);
            for (int i = 0; i < childrenCount; i++) {
                self->playable.ConnectInput(i, self->head.children[i]->BuildPlayableGraph(graph, buildContext), 0);
            }

            return self->playable;
        }

        [BurstCompile]
        [MonoPInvokeCallback(typeof(NodeLink.EvaluateDelegate))]
        private static void Evaluate(in void* node, bool onEnter, in EvaluateContext evaluateContext, in GraphContext graphContext, ref UpstreamData upstream, ref ScopeContext scope) {
            var self = (StateMachineNode*)node;

            // int childrenCount = self->head.childrenCount;
            float deltaTime = evaluateContext.deltaTime;

            if (onEnter) {
                // OnEnter 的这一帧不进行过渡判断，给子节点一个执行 OnEnter() 的机会（可能会设置时间为0，如果先检查就是用不正确的时间了）
                self->currentState = self->defaultState.Evaluate(evaluateContext, graphContext, scope);
                self->transitionEvaluator.SetFirstState(self->currentState);
            } else {
                // 判断是否进入过渡
                bool needTrans = self->transitionInfo.CheckState(self->currentState, *self->head.children[self->currentState], graphContext, out StateMachineTransition transition);
                if (needTrans) {
                    bool addSuccess = self->transitionEvaluator.AddNewState(transition.targetState, transition.duration);
                    if (addSuccess) {
                        self->currentState = transition.targetState;
                    }
                }
            }

            // 计算权重
            self->transitionEvaluator.Evaluate(deltaTime);
            self->transitionEvaluator.GetEnumerator(out TransitionEvaluator.Iter iter);
            while (iter.MoveNext()) {
                var (id, weight) = iter.current;
                var childScope = new ScopeContext(scope, weight);
                self->head.weights[id] = weight;
                NodeLink.Evaluate(self->head.children[id], evaluateContext, graphContext, ref upstream, ref childScope);
                scope.Fusion(childScope);
            }
        }

    }
}
